#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <memory>
#include <map>
#include <set>

using namespace std;

class QueryResult
{
private:
    string sought;
    shared_ptr<vector<string> > file;
    shared_ptr<set<unsigned int> > lines;

public:
    friend ostream &print(ostream &out, const QueryResult &qr);
    QueryResult(string s, shared_ptr<set<unsigned int> > p, shared_ptr<vector<string> > f)
        : sought(s), file(f), lines(p) {}
};
ostream &print(ostream &out, const QueryResult &qr)
{
    out << qr.sought << " occurs " << qr.lines->size() << ' ' << "times"
        << endl;
    for (auto num : *(qr.lines))
    {
        out << "\t(line" << num + 1 << ") " << *(qr.file->begin() + num) << endl;
    }
    return out;
}
class TextQuery
{
private:
    shared_ptr<vector<string> > file;
    map<string, shared_ptr<set<unsigned int> > > wm;

public:
    TextQuery() {}
    TextQuery(ifstream &infile) : file(new vector<string>)
    {
        string tmp;
        while (getline(infile, tmp))
        {
            file->push_back(tmp);
            int lineNo = file->size() - 1; // 当前行号
            istringstream line(tmp);
            string word;
            while (line >> word)
            {
                shared_ptr<set<unsigned int> > &lines = wm[word]; // 注意这是个指针，要new开辟空间
                if (!lines)                                       // 看set中是否已经有了
                    lines.reset(new set<unsigned int>);
                lines->insert(lineNo); // 向set中插入行号
            }
        }
    }
    QueryResult query(const string &s)
    {
        static shared_ptr<set<unsigned int> > nodata(new set<unsigned int>);
        auto loc = wm.find(s);
        if (loc == wm.end())
        {
            return QueryResult(s, nodata, file);
        }
        else
        {
            return QueryResult(s, loc->second, file);
        }
    }
};

void runQueries(ifstream &infile)
{
    TextQuery tq(infile);
    while (true)
    {
        cout << "enter word  or Q to quit ! : ";
        string s;
        if (cin >> s && (s != "q" && s != "Q"))
            print(cout, tq.query(s)) << endl;
        else
            break;
    }
}

int main()
{
    string fileName = "Text.txt";
    ifstream in(fileName);
    if (in.is_open())
    {
        runQueries(in);
    }
    else
        cout << " open file error" << endl;

    return 0;
}
